package hamaster.jpbc.crypt.impl;

import hamaster.jpbc.crypt.Crypt;
import hamaster.jpbc.exception.CryptException;
import hamaster.jpbc.gui.ProgressListener;
import hamaster.jpbc.pbc.PBCDriver;
import hamaster.jpbc.pbc.PrivateKey;
import hamaster.jpbc.pbc.PublicParameter;
import it.unisa.dia.gas.jpbc.Element;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;

public class IBENativeCryptIOImpl extends SimpleCryptIOImpl {

	private String savePath;
	private Element receiver;
	private PublicParameter publicParameter;
	private PrivateKey privateKey;

	private IBENativeCryptIOImpl(String savePath) {
		this.savePath = savePath;
	}

	public IBENativeCryptIOImpl(String savePath,
			Element receiver, PublicParameter publicParameter) {
		this(savePath);
		this.receiver = receiver;
		this.publicParameter = publicParameter;
	}

	public IBENativeCryptIOImpl(String savePath,
			PrivateKey privateKey) {
		this(savePath);
		this.privateKey = privateKey;
	}

	/*
	 * (non-Javadoc)
	 * @see hamaster.jpbc.crypt.impl.SimpleCryptIOImpl#encrypt(java.io.File,
	 * java.io.OutputStream)
	 */
	@Override
	public void encrypt(File source, OutputStream destination)
			throws IOException, CryptException {
		String plain = source.getPath() + "\0";
		String alice = PBCDriver.hex(receiver.toBytes()) + "\0";
		String cipher = savePath + "\0";
		String g = PBCDriver.hex(publicParameter.getG().toBytes()) + "\0";
		String g1 = PBCDriver.hex(publicParameter.getG1().toBytes()) + "\0";
		String h = PBCDriver.hex(publicParameter.getH().toBytes()) + "\0";
		ProgressCallback safe = new ProgressCallback(progressListener);

		IBCLibrary.INSTANCE.encrypt_file_sp(
				plain.getBytes(),
				cipher.getBytes(),
				g.getBytes(),
				g1.getBytes(),
				h.getBytes(),
				alice.getBytes(),
				safe);
	}

	/*
	 * (non-Javadoc)
	 * @see hamaster.jpbc.crypt.impl.SimpleCryptIOImpl#decrypt(java.io.File,
	 * java.io.OutputStream)
	 */
	@Override
	public void decrypt(File source, OutputStream destination)
			throws IOException, CryptException {
		String cipher = source.getPath() + "\0";
		String rID = PBCDriver.hex(privateKey.getrID().toBytes()) + "\0";
		String hID = PBCDriver.hex(privateKey.gethID().toBytes()) + "\0";
		String plain = savePath + "\0";
		ProgressCallback safe = new ProgressCallback(progressListener);

		IBCLibrary.INSTANCE.decrypt_file_sp(
				cipher.getBytes(),
				plain.getBytes(),
				rID.getBytes(),
				hID.getBytes(),
				safe);
	}

	@Override
	public void setCrypt(Crypt crypt) {
		throw new RuntimeException("No need to implement this method!");
	}

	@Override
	public void setBlockSize(int blockSize) {
		throw new RuntimeException("No need to implement this method!");
	}

	public interface IBCLibrary extends Library {
		IBCLibrary INSTANCE = (IBCLibrary) Native.loadLibrary("ibc", IBCLibrary.class);
		int encrypt_file_s(byte[] plain, byte[] cipher, byte[] g, byte[] g1, byte[] h, byte[] alice);
		int decrypt_file_s(byte[] cipher, byte[] plain, byte[] rID, byte[] hID);
		int encrypt_file_sp(byte[] plain, byte[] cipher, byte[] g, byte[] g1, byte[] h, byte[] alice, ProgressCallback update);
		int decrypt_file_sp(byte[] cipher, byte[] plain, byte[] rID, byte[] hID, ProgressCallback update);
	}
}

class ProgressCallback implements Callback {

	private ProgressListener listener;

	public ProgressCallback(ProgressListener listener) {
		this.listener = listener;
	}

	public void callback(int progress) {
		listener.progressUpdated(progress);
	}
}
